package models

import (
	"annual-lottery/models/model"
	"annual-lottery/utils"
	"time"
)

const (
	STATUS_DELETE = iota - 1
	STATUS_READY
	STATUS_NORMAL
)

const (
	DATA_DELETE = iota - 1
	DATA_ADD
	DATA_UPDATE
)

// LotteryModel model
type LotteryModel struct{}

// UserList 用户列表
func (m *LotteryModel) UserList() ([]model.TaUser, error) {
	users := make([]model.TaUser, 0)
	err := Dao.Asc("user_id").Find(&users)
	return users, err
}

// PrizeSettingList 奖品设置列表
func (m *LotteryModel) PrizeSettingList() ([]model.TaPrizeSetting, error) {
	ps := make([]model.TaPrizeSetting, 0)

	err := Dao.Desc("create_date").Find(&ps)
	return ps, err
}

// PrizeSetting 抽奖设置维护
func (m *LotteryModel) PrizeSetting(s *model.TaPrizeSetting, typ int) error {
	switch typ {
	case DATA_ADD:
		s.SettingId = 0
		s.Status = STATUS_NORMAL
		s.CreateDate = time.Now().Local()
		_, err := Dao.Insert(s)
		return err
	case DATA_UPDATE:
		cols := []string{"prize_id", "is_repeat", "prize_num", "status"}
		_, err := Dao.Cols(cols...).Where("setting_id=?", s.SettingId).Update(s)
		return err
	default:
		return nil
	}
}

// Draw 抽奖
// 因为没有库存的概念，因此奖品中奖后, 不会把奖品表中的数量减一
func (m *LotteryModel) Draw() ([]model.TaPrizeWinner, error) {
	// 获取当前可用抽奖设置
	setting := model.TaPrizeSetting{}
	if _, err := Dao.Where("status=?", STATUS_NORMAL).Get(&setting); err != nil {
		return nil, err
	}

	// 获取奖品
	prize := model.TaPrize{}
	if _, err := Dao.Where("prize_id=?", setting.PrizeId).Get(&prize); err != nil {
		return nil, err
	}

	// 获取参与抽奖人员
	users := make([]model.TaUser, 0)
	query := `select * from ta_user t`
	if setting.IsRepeat == 0 {
		// 如果不允许多次中奖
		query += ` where not exists (
			select * from ta_prize_winner s where t.user_id = s.user_id
		)`
	}
	if err := Dao.SQL(query).Find(&users); err != nil {
		return nil, err
	}

	pws := make([]model.TaPrizeWinner, 0)
	randIDs := make([]int, 0)
	randID := -1
	for i := 0; i < setting.PrizeNum; i++ {
		// 获取中奖人员
		for {
			randID = utils.RandNum(len(users))
			if utils.IntSliceIndex(randIDs, randID) > -1 {
				randIDs = append(randIDs, randID)
				break
			}
		}

		winner := users[randID]

		// 组合中奖信息
		pw := model.TaPrizeWinner{
			UserId:     winner.UserId,
			UserName:   winner.UserName,
			UserOrg:    winner.UserOrg,
			UserDept:   winner.UserDept,
			PrizeId:    prize.PrizeId,
			PrizeName:  prize.PrizeName,
			PrizeType:  prize.PrizeType,
			SettingId:  setting.SettingId,
			Status:     STATUS_NORMAL,
			CreateDate: time.Now().Local(),
		}

		pws = append(pws, pw)
	}

	// 更新抽奖配置
	if _, err := Dao.Cols("status").
		Update(&model.TaPrizeSetting{SettingId: setting.SettingId, Status: STATUS_NORMAL}); err != nil {
		return nil, err
	}

	// 保存记录
	if _, err := Dao.Insert(&pws); err != nil {
		return nil, err
	}

	return pws, nil
}

// PrizeEdit 奖品维护
func (m *LotteryModel) PrizeEdit(p *model.TaPrize, typ int) error {
	switch typ {
	case DATA_ADD:
		p.CreateDate = time.Now().Local()
		_, err := Dao.Insert(p)
		return err
	case DATA_UPDATE:
		cols := []string{"prize_type", "prize_name", "picture", "stock"}
		_, err := Dao.Cols(cols...).Where("prize_id=?", p.PrizeId).Update(p)
		return err
	default:
		return nil
	}
}

// PrizeList 奖品列表
func (m *LotteryModel) PrizeList() ([]model.TaPrize, error) {
	ps := make([]model.TaPrize, 0)
	err := Dao.Desc("create_date").Find(&ps)
	return ps, err
}

// WinnerList 中奖人员名单
// typ 奖品类型
// name 用户名称
// del 是否有效记录
func (m *LotteryModel) WinnerList(typ, name string, del ...int) ([]model.TaPrizeWinner, error) {
	ws := make([]model.TaPrizeWinner, 0)
	query := Dao.Where("1=1")

	if typ != "" {
		query = query.And("prize_type like '%" + typ + "%'")
	}

	if name != "" {
		query = query.And("user_name like '%" + name + "%'")
	}

	if len(del) > 0 {
		query = query.And("status=?", del[0])
	}

	err := query.Asc("prize_type").Desc("create_date").Find(&ws)
	return ws, err
}

// CancelWinner 作废中奖人员
func (m *LotteryModel) CancelWinner(prizeID, userID int) error {
	// 作废记录
	pw := model.TaPrizeWinner{Status: STATUS_DELETE}
	if _, err := Dao.Cols("status").Where("prize_id=?", prizeID).
		And("user_id=?", userID).Update(&pw); err != nil {
		return err
	}

	return nil
}
